package com.mybatis.jpa.sqlbuilder;

import com.mybatis.jpa.constants.ParamConstants;
import com.mybatis.jpa.exception.JpaException;
import org.apache.ibatis.reflection.MetaObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class SqlBuilder {

	public abstract String buildSql(MetaObject metaStatementHandler) throws Exception ;
		
	protected void filter(Map<String, Object> paramMap, List<String> columns) {
		List<String> excludeCol = getExcludeColumn(paramMap);
		columns.removeAll(excludeCol);
	}

	protected List<String> getExcludeColumn(Map<String, Object> paramMap) {
		if (!paramMap.containsKey(ParamConstants.EXCLUDE_COLUMN)) {
			return new ArrayList<>();
		} else {
			return (List<String>) paramMap.get(ParamConstants.EXCLUDE_COLUMN);
		}
	}

	/**
	 * 获取调用方法的参数
	 * @param metaStatementHandler
	 * @return
	 */
	protected Map<String, Object> getParamMap(MetaObject metaStatementHandler) {
		/*
		 * 但方法参数只有一个而且没有使用注解@Parma，mybaits就直接获取参数的值，在*mapper.xml的#{}这个占位符花括号里的内容可以写任意字符。
		 * 如果使用只有一个参数并且使用注解@Parma或方法提供多个参数时，mybaits就会把参数值存放在map对象里。
		 * 如果方法提供多个参数并且没有使用注解@Param，map对象key的值是param{1}；第一个参数就是param1，第二个参数是param2，如此类推
		 * */
		Object object = metaStatementHandler.getValue("delegate.boundSql.parameterObject");
		if (object instanceof Map) {
			Map<String, Object> map = (Map<String, Object>) object;
			/*
			 * 如果方法参数只有一个而且是List对象并且没有注解@Param，mybatis把参数存放到map对象，但是会有两个不同的key对应参数，
			 * 一个是key=list，另一个是key=collection
			 */
			if (map.size() == 2 && map.containsKey(ParamConstants.LIST) && map.containsKey("collection")) {
				// 这里重新生成一个key，放到参数map对象里，为了方便在PartTree.OrPart对象使用
				String key = ParamConstants.MYBATIS_PARAM + "1";
				map.put(key, map.get(ParamConstants.LIST));
			}
			return map;
		} else {
			Map<String, Object> map = new HashMap<>();
			map.put(ParamConstants.MYBATIS_PARAM + "1", object);
			return map;
		}
	}

	public List<Object> getInsertParamList(Map<String, Object> parameterMap) {
		List<Object> list;
		Object paramObj = parameterMap.get(ParamConstants.LIST);

		JpaException.NullRuntimeException(paramObj, ParamConstants.LIST + "对象不能为空");

		if (paramObj instanceof List) {
			list = (List<Object>) paramObj;
			JpaException.CollectionIsBlankRuntimeException(list, "List对象不能为空集合");
		} else {
			//将非集合对象封装成集合对象
			list = new ArrayList<>();
			list.add(paramObj);
			parameterMap.put(ParamConstants.LIST, list);
		}
		return list;
	}
}
